ArrayList things;
MultiPalette pal;
boolean bClearScreen = false;
boolean bScaleReduce = true;
boolean bUseColor = true;

void setupConfetti() {
  //smooth();
  things = new ArrayList();
  pal = new MultiPalette("palettes.jpg");
  pal.select();
  //background(255);
  fill(255);
}

void drawConfetti(float myID, float mousex1, float mousey1, float pressure) {
  if (bClearScreen)
  background(255);
  if (myID >=1)
    spawn(mousex1,mousey1);
  if (things.size() > 0) {
    for (int i=0, sz=things.size(); i<sz; i++) {
      ConfettiBase c = (ConfettiBase)things.get(i);
      c.move();
      if (c.alive())
        c.draw(pressure);
      else {
        things.remove(c);
        i--;
        sz--;
      }
    }
  }
}

void spawn(float spawnx, float spawny) {
  int which = (int)(random(8));
  switch(which) {
    case 0 : things.add( new ConfettiRectangle(spawnx,spawny) ); break;
    case 1 : things.add( new ConfettiTriangle(spawnx,spawny) );  break;
    case 2 : things.add( new ConfettiParallelogram(spawnx,spawny) ); break;
    case 3 : things.add( new ConfettiHexagon(spawnx,spawny) ); break;
    case 4 : things.add( new ConfettiPentagon(spawnx,spawny) ); break;
    case 5 : things.add( new ConfettiStar(spawnx,spawny) ); break;
    case 6 : things.add( new ConfettiBoomerang(spawnx,spawny) ); break;
    case 7 : things.add( new ConfettiShuriken(spawnx,spawny) ); break;
  } 
}
class ConfettiBase {
  float x, y;
  float ox, oy;
  float vel, dvel, ddvel;
  float ang, dang, ddang;
  float t;
  float wid,hei;
  color c;
  ConfettiBase(float _x, float _y) {
    x = _x;
    y = _y;
    t = 0.0;
    wid = random(1.0,20.0);
    hei = random(1.0,20.0);
    c = (bUseColor) ? pal.get() : color(0);
    vel = random(1.0,4.0);
    dvel = random(0.001,0.01);
    ddvel = random(0.0001,0.001);
    ang = random(-PI,PI);
    dang = random(-0.01,0.01);
    ddang = random(-0.001,0.001);
  }
  boolean alive() { return (t < 1.0); }
  void move() {
    ox = x;
    oy = y;
    dang += ddang;
    ang += dang;
    dvel += ddvel;
    vel += dvel;
    vel *= 0.9;
    x += vel * cos(ang);
    y += vel * sin(ang);
    t += 0.01;
  };
  void draw(float pressure) {
    stroke(red(c), green(c), blue(c), 255f-t*255f);
    fill(255, 255-t*255f);
    pushMatrix();
    translate(x,y);
    float theta = atan2(y-oy,x-ox);
    rotate(theta);
    if (bScaleReduce)
      scale(1.0-t*0.9);
    shape();
    popMatrix();
  };
  void shape() {
  }
}


class ConfettiRectangle extends ConfettiBase {
  ConfettiRectangle(float _x, float _y) { super(_x,_y); } 
  void shape() {
    beginShape(POLYGON);
    vertex(-wid,-hei);
    vertex(wid,-hei);
    vertex(wid,hei);
    vertex(-wid,hei);
    vertex(-wid,-hei);
    endShape();
  }
}

class ConfettiTriangle extends ConfettiBase {
  ConfettiTriangle(float _x, float _y) { super(_x,_y); } 
  void shape() {
    beginShape(POLYGON);
    vertex(-wid/2,-hei);
    vertex(wid,0);
    vertex(-wid/2,hei);
    vertex(-wid/2,-hei);
    endShape();
  }
}

class ConfettiParallelogram extends ConfettiBase {
  ConfettiParallelogram(float _x, float _y) { super(_x,_y); } 
  void shape() {
    beginShape(POLYGON);
    vertex(-wid,-hei);
    vertex(-wid/2,hei);
    vertex(wid,hei);
    vertex(wid/2,-hei);
    vertex(-wid,-hei);
    endShape();
  }
}

class ConfettiPentagon extends ConfettiBase {
  ConfettiPentagon(float _x, float _y) { super(_x,_y); } 
  void shape() {
    beginShape(POLYGON);
    vertex(-wid/2,-hei/2);
    vertex(wid/2,-hei);
    vertex(wid,0);
    vertex(wid/2,hei);
    vertex(-wid/2,hei/2);
    vertex(-wid/2,-hei/2);
    endShape();
  }
}

class ConfettiHexagon extends ConfettiBase {
  ConfettiHexagon(float _x, float _y) { super(_x,_y); } 
  void shape() {
    beginShape(POLYGON);
    vertex(-wid,0);
    vertex(-wid/2,hei);
    vertex(wid/2,hei);
    vertex(wid,0);
    vertex(wid/2,-hei);
    vertex(-wid/2,-hei);
    vertex(-wid,0);
    endShape();
  }
}

class ConfettiStar extends ConfettiBase {
  ConfettiStar(float _x, float _y) { super(_x,_y); } 
  void shape() {
    beginShape(POLYGON);
    vertex(-wid/2,0);
    vertex(-wid,hei);
    vertex(0,hei/2);
    vertex(wid/2,hei*3/2);
    vertex(wid/2,hei/2);
    vertex(wid*3/2,0);
    vertex(wid/2,-hei/2);
    vertex(wid/2,-hei*3/2);
    vertex(0,-hei/2);
    vertex(-wid,-hei);
    vertex(-wid/2,0);
    endShape();
  }
}

class ConfettiBoomerang extends ConfettiBase {
  ConfettiBoomerang(float _x, float _y) { super(_x,_y); } 
  void shape() {
    beginShape(POLYGON);
    vertex(0,hei/2);
    vertex(-wid,hei);
    vertex(wid,hei/2);
    vertex(wid,-hei/2);
    vertex(-wid,-hei);
    vertex(0,-hei/2);
    vertex(0,hei/2);
    endShape();
  }
}

class ConfettiShuriken extends ConfettiBase {
  ConfettiShuriken(float _x, float _y) { super(_x,_y); } 
  void shape() {
    beginShape(POLYGON);
    vertex(-wid*3/2,0);
    vertex(0,hei/2);
    vertex(0,hei*3/2);
    vertex(wid/2,0);
    vertex(wid*3/2,0);
    vertex(0,-hei/2);
    vertex(0,-hei*3/2);
    vertex(-wid/2,0);
    vertex(-wid*3/2,0);
    endShape();
  }
}

class MultiPalette {
  PImage img;
  int numPalettes, curPalette;
  MultiPalette(String filename) {
    img = loadImage(filename);
    numPalettes = img.height / 10;
    curPalette = 0;
  }
  void select() {
    curPalette = int(random(numPalettes));
  }
  color get() {
    return img.get(int(random(img.width)), curPalette*10+int(random(10)));
  }
}
